package edu.wpi.cs509.representation;

import java.io.ObjectStreamException;
import java.io.Serializable;

/**
 * The basic board piece types and their static attributes. 
 * 
 * This class stores the basic attributes of a piece. Rank, printable name, and
 * number of instances of this piece per player.
 * 
 * Rank is defined per the game rules where applicable. Note: Spy, Bomb, and Flag do not have a rank 
 * in the game rules. Lower rank wins in battles. 
 * <pre>
 * Marshal = 1 
 * General = 2
 * Colonels = 3
 * Majors = 4
 * Captains = 5
 * Lieutenants = 6
 * Sergeants = 7
 * Miners = 8
 * Scouts = 9
 * Spy = 10
 * Bomb = 0
 * Flag = 11
 * </pre>
 * 
 * It also instantiates global objects for each piece type that can be used for 
 * building the initial game board.
 * 
 * Finally, a Hidden piece type is available for use in game boards that are passed to 
 * clients where one side of the board must be obscured. Rank of hidden piece types is 
 * defaults to -1, though no one should request rank for a hidden piece type. 
 * 
 * @author Jay Lubomirski
 * @see edu.wpi.cs509.representation.PlayerPiece
 */
public class StrategoPiece extends StrategoObjectBc implements Serializable,Cloneable {
	
	private static final long serialVersionUID = 1L; // Version of structure for messages.
	private int pieceRank; // Rank of piece, see comments in class definition.
	private int numberPerUser; // number of this type of piece
	private String pieceName; // printable string for this piece type

	/* 
	 * Default rank values for the piece types 
	 */
	static final int MARSHAL_RANK = 1;
	static final int GENERAL_RANK = 2; 
	static final int COLONEL_RANK = 3;
	static final int MAJOR_RANK = 4;
	static final int CAPTAIN_RANK = 5;
	static final int LIEUTENANT_RANK = 6;
	static final int SERGEANT_RANK = 7;
	static final int MINER_RANK = 8;
	static final int SCOUT_RANK = 9;
	static final int SPY_RANK = 10;
	static final int BOMB_RANK = 0;
	static final int FLAG_RANK = 11;
	static final int HIDDEN_RANK = -1;
	
	/**
	 * Constructor for StrategoPiece class
	 * @param name Printable string for piece type
	 * @param Rank Rank of Piece based on the game rules @see StrategoPiece for details.
	 * @param numberOfPiecesPerPlayer
	 */
	private StrategoPiece(String name, int Rank, int numberOfPiecesPerPlayer) {
		super(name);
		pieceRank = Rank;
		pieceName = name;
		numberPerUser = numberOfPiecesPerPlayer;
	}

    protected Object clone(TeamColor mask) throws CloneNotSupportedException {
        Object cloneGb = super.clone();				
        return cloneGb;
    }	
	
	/** 
	 * Return a printable string of the piece type. 
	 */
	public String toString() {
		return pieceName;
	}

	/**
	 * The number of this piece type per user in a game.
	 * @return the number of this piece type per user in a game.
	 */
	public int numberPerUser() {
		return numberPerUser;
	}
	
	/**
	 * Determine maximum movement for piece in a turn.
	 * @return The number of spaces a piece can theoretically move in a turn. 
	 */
	public int maxSpacesCanMove() {
		if (pieceRank == SCOUT_RANK) // Scout can move up to the whole board length in any direction.
			return (10);
		else 
			if ((pieceRank == FLAG_RANK) || 
				(pieceRank == BOMB_RANK) || 
				(pieceRank == HIDDEN_RANK))  // bomb, flag, or hidden
				return (0);
			else
				return (1);
	}

	/**
	 * Get the rank of a piece. 
	 * @return The numerical rank of piece.
	 * 
	 * @throws UnsupportedOperationException if the piece is hidden
	 */
	public int getRank() {
		if (pieceRank == HIDDEN_RANK)
				throw new UnsupportedOperationException();
		return pieceRank;
	}

	/** 
	 * Determine if piece can kill a Marshal if it attacks one. 
	 * @return true if piece can kill a Marshal
	 * 
	 * @throws UnsupportedOperationException if the piece is hidden
	 */
	public boolean canKillAMarshal() {
		if (pieceRank == HIDDEN_RANK)
			throw new UnsupportedOperationException();
		return (pieceRank == SPY_RANK); // Only a Spy can kill a bomb
	}

	/**
	 * Determine if piece can destroy a bomb. 
	 * @return true if piece can destroy a bomb.
	 * 
	 * @throws UnsupportedOperationException if the piece is hidden
	 */
	public boolean canKillABomb() {
		if (pieceRank == HIDDEN_RANK)
			throw new UnsupportedOperationException();
		return (pieceRank == MINER_RANK); // Only a Miner can kill a bomb
	}

	/**
	 * Resolve which StrategoPiece should be used during de-serialization
	 * @return Object Reference to singleton
	 * @throws ObjectStreamException
	 */
	private Object readResolve() throws ObjectStreamException {
		switch (pieceRank) {
		case MARSHAL_RANK:
			return MARSHAL;
		case GENERAL_RANK:
			return GENERAL;
		case COLONEL_RANK:
			return COLONEL;
		case MAJOR_RANK:
			return MAJOR;
		case CAPTAIN_RANK:
			return CAPTAIN;
		case LIEUTENANT_RANK:
			return LIEUTENANT;
		case SERGEANT_RANK:
			return SERGEANT;
		case MINER_RANK:
			return MINER;
		case SCOUT_RANK:
			return SCOUT;
		case SPY_RANK:
			return SPY;
		case BOMB_RANK:
			return BOMB;
		case FLAG_RANK:
			return FLAG;
		case HIDDEN_RANK:
			return HIDDEN;
		default:
			return null;
		}
	}
	
	/*
	 * Create default piece types available for use everywhere
	 */
	
	/** 
	 * Marshal Piece type
	 */
	public static final StrategoPiece MARSHAL = new StrategoPiece("Marshal", MARSHAL_RANK, 1);

	/**
	 * General Piece type
	 */
	public static final StrategoPiece GENERAL = new StrategoPiece("General", GENERAL_RANK, 1);
	
	/**
	 * Colonel Piece type
	 */
	public static final StrategoPiece COLONEL = new StrategoPiece("Colonel", COLONEL_RANK, 2);
	
	/**
	 * Major Piece type
	 */
	public static final StrategoPiece MAJOR = new StrategoPiece("Major", MAJOR_RANK, 3);
	
	/**
	 * Captain Piece type
	 */
	public static final StrategoPiece CAPTAIN = new StrategoPiece("Captain", CAPTAIN_RANK, 4);
	
	/**
	 * Lieutenant Piece type
	 */
	public static final StrategoPiece LIEUTENANT = new StrategoPiece("Lieutenant", LIEUTENANT_RANK, 4);
	
	/**
	 * Sergeant Piece type
	 */
	public static final StrategoPiece SERGEANT = new StrategoPiece("Sergeant", SERGEANT_RANK, 4);
	
	/**
	 * Miner Piece type
	 */
	public static final StrategoPiece MINER = new StrategoPiece("Miner", MINER_RANK, 5);
	
	/**
	 * Scout Piece type
	 */
	public static final StrategoPiece SCOUT = new StrategoPiece("Scout", SCOUT_RANK, 8);
	
	/**
	 * Spy Piece type
	 */
	public static final StrategoPiece SPY = new StrategoPiece("Spy", SPY_RANK, 1);
	
	/**
	 * Bomb Piece type
	 */
	public static final StrategoPiece BOMB = new StrategoPiece("Bomb", BOMB_RANK, 6);
	
	/**
	 * Flag Piece type
	 */
	public static final StrategoPiece FLAG = new StrategoPiece("Flag", FLAG_RANK, 1);
	
	/** 
	 * Array of all the game piece types for use in creating the game board.
	 */
	public static final StrategoPiece ALL_GAME_PIECES[] = { MARSHAL, GENERAL, COLONEL, MAJOR, CAPTAIN, 
			LIEUTENANT, SERGEANT, MINER, SCOUT, SPY, BOMB, FLAG };
	
	/**
	 * Hidden piece type for obscuring gameboard pieces when sent to client
	 */
	public static final StrategoPiece HIDDEN = new StrategoPiece("Hidden", HIDDEN_RANK, 40);
}
